package org.example.config;

import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.example.ann.DynamicExecutor;
import org.example.ann.DynamicJob;
import org.example.service.XxlJobConfigService;
import org.example.service.XxlJobExecutorApi;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;

@Configuration
@Data
@Slf4j
public class XxlJobScan implements ApplicationContextAware, CommandLineRunner {

    private  ApplicationContext applicationContext;


    @Autowired
    private XxlJobExecutorApi xxlJobExecutorApi;

    @Autowired
    private XxlJobConfigService xxlJobConfigService;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;

    }

    /**
     * 扫描所有组件中带有特定注解的方法
     *
     * @param annotationClass 要扫描的注解类型
     * @return 包含注解和方法信息的列表
     */
    public <A  extends Annotation> List<AnnotatedMethod<A>> scanForAnnotatedMethods(Class<A> annotationClass) {
        List<AnnotatedMethod<A>> result = new ArrayList<>();

        // 获取所有组件 Bean 名称
        String[] beanNames = applicationContext.getBeanNamesForAnnotation(Component.class);

        for (String beanName : beanNames) {
            Object bean = applicationContext.getBean(beanName);
            Class<?> beanClass = getTargetClass(bean);

            // 扫描类中的方法
            ReflectionUtils.doWithMethods(beanClass, method -> {
                // 检查方法是否有目标注解
                if (method.isAnnotationPresent(annotationClass)) {
                    A annotation = method.getAnnotation(annotationClass);
                    result.add(new AnnotatedMethod<>(annotation, method, bean));
                }
            });
        }

        return result;
    }



    /**
     * 获取目标类（处理代理类）
     */
    private Class<?> getTargetClass(Object bean) {
        // 获取实际目标类（处理Spring AOP代理）
        return ClassUtils.getUserClass(bean);
    }


    @Data
    public static class XxlJobInfoAnno{
        private final DynamicJob dynamicJob;
        private final XxlJob xxlJob;
    }

    @Override
    public void run(String... args) throws Exception {
        List<AnnotatedMethod<DynamicJob>> dynamicJobs = scanForAnnotatedMethods(DynamicJob.class);
        Set<String> executorNames = new HashSet<>();
        List<DynamicExecutor> executors = new ArrayList<>();
        List<XxlJobInfoAnno> jobInfos = new ArrayList<>();
        for (AnnotatedMethod<DynamicJob> dynamicJob : dynamicJobs) {
            XxlJob xxlJob = dynamicJob.getMethod().getAnnotation(XxlJob.class);
            if(xxlJob ==null){
                // 类名  方法明  上缺少xxlJob注解
                log.info("{} 类 {} 方法上缺少 xxlJob 注解",dynamicJob.getBean().getClass().getCanonicalName(),dynamicJob.getMethod().getName());
                throw new RuntimeException("类 " + dynamicJob.getBean().getClass().getCanonicalName() + " 方法 " + dynamicJob.getMethod().getName() + " 上缺少 xxlJob 注解");
            }
            DynamicExecutor executor = dynamicJob.annotation.executor();
            if(executor ==null){
                log.info("{} 类 {} 方法上缺少 DynamicExecutor 注解",dynamicJob.getBean().getClass().getCanonicalName(),dynamicJob.getMethod().getName());
                throw new RuntimeException("类 " + dynamicJob.getBean().getClass().getCanonicalName() + " 方法 " + dynamicJob.getMethod().getName() + " 上缺少 DynamicExecutor 注解");
            }
            if(executorNames.contains(executor.name())){
                log.info("{} 类 {} 方法上 DynamicExecutor 的 name 属性值重复",dynamicJob.getBean().getClass().getCanonicalName(),dynamicJob.getMethod().getName());
            }
            executors.add(executor);
            XxlJobInfoAnno  xxlJobInfoAnno = new XxlJobInfoAnno(dynamicJob.annotation, xxlJob);
            jobInfos.add(xxlJobInfoAnno);
        }
        if(!executors.isEmpty()){
            xxlJobConfigService.createIfNotExist(executors);
        }

        if(!jobInfos.isEmpty()){
            xxlJobConfigService.createJobIfNotExist(jobInfos);
        }



    }

    /**
     * 带注解的方法信息封装类
     */
    public static class AnnotatedMethod<A> {
        private final A annotation;
        private final Method method;
        private final Object bean;

        public AnnotatedMethod(A annotation, Method method, Object bean) {
            this.annotation = annotation;
            this.method = method;
            this.bean = bean;
        }

        public A getAnnotation() {
            return annotation;
        }

        public Method getMethod() {
            return method;
        }

        public Object getBean() {
            return bean;
        }

        /**
         * 执行带注解的方法
         */
        public Object invoke(Object... args) {
            try {
                // 设置方法可访问（处理私有方法）
                method.setAccessible(true);
                return method.invoke(bean, args);
            } catch (Exception e) {
                throw new RuntimeException("执行方法失败: " + method.getName(), e);
            }
        }
    }
}